package org.summer.generator;

import org.reflections.Reflections;
import org.summer.generator.channel.DefaultFileWriterChannel;
import org.summer.generator.channel.FileWriterChannel;
import org.summer.generator.config.CreateConfig;
import org.summer.generator.config.DatabaseConfig;
import org.summer.generator.config.ProjectConfig;
import org.summer.generator.config.WriterConfig;
import org.summer.generator.handler.DatabaseHandler;
import org.summer.generator.handler.DefaultDatabaseHandler;
import org.summer.generator.handler.DefaultFileCreateHandler;
import org.summer.generator.handler.FileCreateHandler;
import org.summer.generator.log.Logger;
import org.summer.generator.log.LoggerManager;
import org.summer.generator.resolver.TableResolver;
import org.summer.generator.vo.Table;
import org.summer.generator.writer.FileWriter;

import java.io.File;
import java.io.FileNotFoundException;
import java.lang.reflect.InvocationTargetException;
import java.nio.channels.FileChannel;
import java.sql.SQLException;
import java.util.List;
import java.util.Set;

/**
 * 文件创建功能委屈类,此类承载了全部的文件写入创建代码的中间操作
 */
public class FileCreateDelegate {
    private static final Logger log = LoggerManager.getLogger(FileCreateDelegate.class);
    private final DatabaseConfig databaseConfig;
    private final ProjectConfig projectConfig;
    private final CreateConfig createConfig;
    private final WriterConfig writerConfig;
    private final FileCreateHandler fileCreate;
    public FileCreateDelegate(DatabaseConfig databaseConfig, ProjectConfig projectConfig, CreateConfig createConfig, WriterConfig writerConfig) {
        this.databaseConfig = databaseConfig;
        this.projectConfig = projectConfig;
        this.createConfig = createConfig;
        this.writerConfig = writerConfig;
        this.fileCreate = new DefaultFileCreateHandler(projectConfig,createConfig);
        this.createDir();
    }

    /**
     * 创建文件夹
     */
    private void createDir(){
        log.debug("创建各层文件夹：" + createConfig.isCreateDir());
        if (createConfig.isCreateDir()){
            fileCreate.createDir();
        }
    }

    /**
     * 根据数据表名字解析table对象
     * @param tableName
     * @return
     */
    private Table parseTable(String tableName){
        DatabaseHandler handler = new DefaultDatabaseHandler();
        handler.setConfig(databaseConfig);
        handler.connect();
        TableResolver resolver = new TableResolver(handler.getConnection());
        Table table = resolver.parseTableFormTableName(tableName);
        handler.close();
        return table;
    }

    /**
     * 根据数据表生成代码写入到文件
     * @param tableName 数据表名字
     */
    public void writerCodeToFile(String tableName) {
       Table table = parseTable(tableName);
       // 1. 获取系统中全部文件写入类接口实现类
        List<Class<? extends FileWriter>> fws = getFileWriterClasses();
        fws.forEach(fw -> {
            File file = fileCreate.createFile(fw, table.getTableUpperName());
            if (file == null){
                return;
            }
            try {
                FileWriterChannel channel = new DefaultFileWriterChannel(file);
                FileWriter fileWriter = fw.getConstructor().newInstance();
                fileWriter.setChannel(channel);
                fileWriter.execute();
                channel.close();
            } catch (Exception e) {
                log.error("创建文件写入通道出错：%s".formatted(fw.getSimpleName()),e);
                throw new RuntimeException(e);
            }
        });

//        fileCreate.createFile(
//        文件的位置（资源路径或者类路径），使用FileWriter 获取
//         文件的包名字或者资源路径的资源目录名字，
//        文件名字，不需后缀
//        );


        // 创建File 对象
        // 根据文件对象创建文件写入通道Channel

        // 批量获取文件写入类对象 FileWriter 接口实现类对象
        // 调用FileWriter.writer()方法写入文件
    }

    /**
     * 获取全部的文件代码写入处理类 类对象
     */
    private List<Class<? extends FileWriter>> getFileWriterClasses() {
        Reflections reflections = new Reflections("org.summer.generator.writer.impl");
        Set<Class<? extends FileWriter>> subTypesOf = reflections.getSubTypesOf(FileWriter.class);
        return subTypesOf.stream().filter(c -> c.getName().contains("impl")).toList();
    }
}
